package ua.dp.mzav.train.tm.model;

import java.io.Serializable;
import org.joda.time.DateTimeConstants;
import org.joda.time.LocalDate;

/** This abstract class represents request of "day off" for an Employee.
 *
 * This class is actually immutable, but child classes should not be immutable
 * (except data are provided by this class).
 */
public abstract class LeaveRequest implements Serializable
{

    private static final long serialVersionUID = 1L;

    /**
     * @serial Not null. Employer who has requested it.
     */
    private final EmployeeReadable employee;
    /**
     * @serial Not null. Date of the begin of the period.
     */
    private final LocalDate begin;
    /**
     * @serial Not null. Date of the end of the period.
     */
    private final LocalDate end;

    /** Constructor
     * @param[in] anEmployee Should be not null.
     * @param[in] aBegin Begin of the requesting period - should be not null.
     * @param[in] anEnd End of the requesting period - should be not null 
     *            and be equal to or later than aBegin.
     * 
     * @invariant getBegin().compare(getEnd()) <= 0
     */
    protected LeaveRequest(final EmployeeReadable anEmployee,
                           final LocalDate aBegin, final LocalDate anEnd
    )
    {
        if (anEmployee == null)
        {
            throw new IllegalArgumentException("Employee is not specified for LeaveRequest");
        }
        if (aBegin == null)
        {
            throw new IllegalArgumentException("Begin of period is not specified for LeaveRequest");
        }
        if (anEnd == null)
        {
            throw new IllegalArgumentException("End of period is not specified for LeaveRequest");
        }
        if (aBegin.compareTo(anEnd) > 0)
        {
            throw new IllegalArgumentException("Invalid period is specified for LeaveRequest");
        }
        
        employee = anEmployee;
        begin = aBegin;
        end = anEnd;
    }
    
    /** Employee has requested the day off.
     * 
     * @return Not null.
     */
    public final EmployeeReadable getEmployee()
    {
        return employee;
    }
    
    /** Begin of the day off period.
     * @return Not null.
     * @see LeaveRequest#getEnd()
     */
    public final LocalDate getBegin()
    {
        return begin;
    }
    
    /** End of the day off period.
     * @return Not null.
     * @see LeaveRequest#getBegin()
     */
    public final LocalDate getEnd()
    {
        return end;
    }
    
    /** Calculates number of working days that are inside the interval.
     * 
     * Assumes Saturday and Sunday are always not working days.
     * 
     * No holidays (no Requirements).
     * 
     * @return Number of working days.
     * 
     * @todo Maybe not too optimal.
     */
    public final int getNumberOfWorkingDays()
    {
        int retVal = 0;
        
        for (LocalDate d=begin; !d.isAfter(end); d=d.plusDays(1))
        {
            final int dayOfWeek = d.getDayOfWeek();
            if (dayOfWeek != DateTimeConstants.SATURDAY  &&
                dayOfWeek != DateTimeConstants.SUNDAY
               )
            {
                ++retVal;
            }
        }

        return retVal;
    }
}
